#include "board.h"
#include "fs_manager.h"
#include "esp_spiffs.h"
#include "esp_vfs_fat.h"

#define TAG "FS_MANAGER"

struct fs_manager_t {
    uint8_t sd_volume : 1;
    sdmmc_card_t *card;
    SemaphoreHandle_t fs_mutex;
};

struct fs_manager_t fs_manager;
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
sdmmc_slot_config_t slot_config = {\
    .clk = BSP_SD_CLK, \
    .cmd = BSP_SD_CMD, \
    .d0 = BSP_SD_D0, \
    .cd = SDMMC_SLOT_NO_CD, \
    .wp = SDMMC_SLOT_NO_WP, \
    .width   = 1, \
    .flags = SDMMC_SLOT_FLAG_INTERNAL_PULLUP, \
};

bool fs_manager_get_sd_volume_state()
{
    return fs_manager.sd_volume;
}

bool sd_card_get_state(void)
{
    if(fs_manager.card == NULL || !fs_manager.sd_volume) {
        return false;
    }

    xSemaphoreTake(fs_manager.fs_mutex, pdMS_TO_TICKS(1000));
    esp_err_t ret = sdmmc_get_status(fs_manager.card);
    xSemaphoreGive(fs_manager.fs_mutex);

    // printf("sdmmc_get_status: %d\n", ret);

    if (ret != ESP_OK) {
        return false;
    }

    return true;
}

esp_err_t sd_sdiofs_mount(void)
{
    esp_err_t ret;

    if (fs_manager.card && fs_manager.sd_volume) {
        ESP_LOGW(TAG, "SD card is already mounted");
        return ESP_OK;
    }

    xSemaphoreTake(fs_manager.fs_mutex, portMAX_DELAY);

    esp_vfs_fat_sdmmc_mount_config_t mount_config = {
        .format_if_mount_failed = false,   // 如果挂载不成功是否需要格式化SD卡
        .max_files = 5, // 允许打开的最大文件数
        .allocation_unit_size = 16 * 1024  // 分配单元大小
    };

    ESP_LOGI(TAG, "Mounting filesystem");

    ret = esp_vfs_fat_sdmmc_mount(SD_MOUNT_POINT, &host, &slot_config, &mount_config, &fs_manager.card); // 挂载SD卡
    if (ret == ESP_OK) {
        fs_manager.sd_volume = true;
        sdmmc_card_print_info(stdout, fs_manager.card);
    } else {
        ESP_LOGE(TAG, "Failed to mount filesystem (%s)", esp_err_to_name(ret));
    }

    xSemaphoreGive(fs_manager.fs_mutex);

    return ret;
}

esp_err_t sd_sdiofs_unmount(void)
{
    esp_err_t ret = ESP_OK;

    if (!fs_manager.card || !fs_manager.sd_volume) {
        ESP_LOGW(TAG, "SD card is not mounted");
        return ESP_OK;
    }

    xSemaphoreTake(fs_manager.fs_mutex, portMAX_DELAY);

    ESP_LOGI(TAG, "Unmounting filesystem");

    ret = esp_vfs_fat_sdcard_unmount(SD_MOUNT_POINT, fs_manager.card);
    if (ret == ESP_OK) {
        fs_manager.sd_volume = false;
    } else {
        ESP_LOGE(TAG, "Failed to unmount filesystem (%s)", esp_err_to_name(ret));
    }
    fs_manager.card = NULL;

    xSemaphoreGive(fs_manager.fs_mutex);

    return ret;
}

esp_err_t bsp_spiffs_mount(void)
{
    esp_vfs_spiffs_conf_t conf = {
        .base_path = SPIFFS_BASE,
        .partition_label = "storage",
        .max_files = 5,
        .format_if_mount_failed = false,
    };

    esp_err_t ret_val = esp_vfs_spiffs_register(&conf);

    ESP_ERROR_CHECK(ret_val);

    size_t total = 0, used = 0;
    ret_val = esp_spiffs_info(conf.partition_label, &total, &used);
    if (ret_val != ESP_OK) {
        ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret_val));
    } else {
        ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
    }

    return ret_val;
}

void fs_manager_init(void)
{
    memset(&fs_manager, 0, sizeof(fs_manager));

    fs_manager.fs_mutex = xSemaphoreCreateMutex();

    bsp_spiffs_mount();

    sd_sdiofs_mount();
}
